﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	ClientAssets.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Web.UI;
using Microsoft.SharePoint.WebControls;

namespace Smart.Common
{
	/// <summary>
	/// Client assets registration helper
	/// </summary>
	[Localizable(false)]
	public static class ClientAssets
	{
		/// <summary>
		/// Client asset type
		/// </summary>
		public enum AssetType
		{
			/// <summary>
			/// Java script
			/// </summary>
			Script,

			/// <summary>
			/// Css
			/// </summary>
			Css
		}

		/// <summary>
		/// Client asset information
		/// </summary>
		public class AssetInfo
		{
			public string Key;
			public AssetType Type;
			public string Src;
			public bool Localizable;
			public bool Defer;
			public bool EnableTheming;

			/// <summary>
			/// Client asset information
			/// </summary>
			public AssetInfo(string key, AssetType type, string src)
			{
				Key = key;
				Type = type;
				Src = src;
			}
		}

		/// <summary>
		/// Client asset registration information
		/// </summary>
		public class AssetRegistrationInfo
		{
			public Control Ctrl;
			public string Key;
			public AssetType Type;
			public string Src;

			public AssetInfo Info;
			public string Param;

			/// <summary>
			/// Client asset registration information
			/// </summary>
			public AssetRegistrationInfo(Control ctrl, AssetInfo info, string param)
			{
				Ctrl = ctrl;
				Info = info;
				Param = param;

				Type = info.Type;
				Key = param == null ? info.Key : string.Format(info.Key, param);
				Src = param == null ? info.Src : string.Format(info.Src, param);
			}

			/// <summary>
			/// Client asset registration information
			/// </summary>
			public AssetRegistrationInfo(Control ctrl, string key, AssetType type, string src)
			{
				Ctrl = ctrl;
				Key = key;
				Type = type;
				Src = src;

				Info = null;
				Param = null;
			}
		}

		// ReSharper disable InconsistentNaming
#if DEBUG
		public const string jQueryKey = "jquery.js";
		public const string jQuerySrc = "~/_layouts/jQuery/jquery-1.7.2.js";

		public const string jQueryMetadataKey = "jquery.metadata.js";
		public const string jQueryMetadataSrc = "~/_layouts/jQuery/jquery.metadata.js";

		public const string jQueryBgIframeKey = "jquery.bgiframe.js";
		public const string jQueryBgIframeSrc = "~/_layouts/jQuery/jquery.bgiframe-2.1.2.js";

		public const string jQueryUIKey = "jquery-ui.js";
		public const string jQueryUISrc = "~/_layouts/jQuery/jquery-ui-1.8.18.js";
		public const string jQueryUIThemeKey = "jquery-ui.css";
		public const string jQueryUIThemeSrc = "~/_layouts/jQuery/themes/{0}/jquery-ui-1.8.18.css";

		public const string jQueryValidateKey = "jquery.validate.js";
		public const string jQueryValidateSrc = "~/_layouts/jQuery/jquery.validate.js";
		public const string jQueryValidateAdditionalKey = "additional-methods.js";
		public const string jQueryValidateAdditionalSrc = "~/_layouts/jQuery/additional-methods.js";
		public const string jQueryValidateMessagesKey = "messages_{0}.js";
		public const string jQueryValidateMessagesSrc = "~/_layouts/jQuery/localization/messages_{0}.js";

		public const string jQueryMobileKey = "jquery.mobile.js";
		public const string jQueryMobileSrc = "~/_layouts/jQuery/mobile/jquery.mobile-1.1.0.js";
		public const string jQueryMobileThemeKey = "jquery.mobile.css";
		public const string jQueryMobileThemeSrc = "~/_layouts/jQuery/mobile/themes/{0}/jquery.mobile-1.1.0.css";

		public const string Base64Key = "base64.js";
		public const string Base64Src = "~/_layouts/Smart.Common/base64.js";

		public const string QSValuesKey = "qsvalues.js";
		public const string QSValuesSrc = "~/_layouts/Smart.Common/qsvalues.js";

		public const string SPHelpersKey = "sphelpers.js";
		public const string SPHelpersSrc = "~/_layouts/Smart.Common/sphelpers.js";

		public const string SPUtilityKey = "sputility.js";
		public const string SPUtilitySrc = "~/_layouts/Smart.Common/sputility.js";

		public const string UrlCodingKey = "urlcoding.js";
		public const string UrlCodingSrc = "~/_layouts/Smart.Common/urlcoding.js";

		public const string FormsKey = "forms.css";
		public const string FormsSrc = "forms.css";

		public const string FormTabsKey = "formtabs.css";
		public const string FormTabsSrc = "~/_layouts/Smart.Common/formtabs.css";

#else
		public const string jQueryKey = "jquery.js";
		public const string jQuerySrc = "~/_layouts/jQuery/jquery-1.7.2.min.js";

		public const string jQueryMetadataKey = "jquery.metadata.js";
		public const string jQueryMetadataSrc = "~/_layouts/jQuery/jquery.metadata.js";

		public const string jQueryBgIframeKey = "jquery.bgiframe.js";
		public const string jQueryBgIframeSrc = "~/_layouts/jQuery/jquery.bgiframe-2.1.2.js";

		public const string jQueryUIKey = "jquery-ui.js";
		public const string jQueryUISrc = "~/_layouts/jQuery/jquery-ui-1.8.18.min.js";
		public const string jQueryUIThemeKey = "jquery-ui.css";
		public const string jQueryUIThemeSrc = "~/_layouts/jQuery/themes/{0}/jquery-ui-1.8.18.css";

		public const string jQueryValidateKey = "jquery.validate.js";
		public const string jQueryValidateSrc = "~/_layouts/jQuery/jquery.validate.min.js";
		public const string jQueryValidateAdditionalKey = "additional-methods.js";
		public const string jQueryValidateAdditionalSrc = "~/_layouts/jQuery/additional-methods.min.js";
		public const string jQueryValidateMessagesKey = "messages_{0}.js";
		public const string jQueryValidateMessagesSrc = "~/_layouts/jQuery/localization/messages_{0}.js";

		public const string jQueryMobileKey = "jquery.mobile.js";
		public const string jQueryMobileSrc = "~/_layouts/jQuery/mobile/jquery.mobile-1.1.0.min.js";
		public const string jQueryMobileThemeKey = "jquery.mobile.css";
		public const string jQueryMobileThemeSrc = "~/_layouts/jQuery/mobile/themes/{0}/jquery.mobile-1.1.0.min.css";
#endif
		// ReSharper restore InconsistentNaming

		/// <summary>
		/// 
		/// </summary>
		public static SyncDictionary<string, AssetInfo> Storage;

		/// <summary>
		/// Client assets registration helper
		/// </summary>
		static ClientAssets()
		{
			Storage =
				new SyncDictionary<string, AssetInfo>(StringComparer.OrdinalIgnoreCase)
					{
						{jQueryKey, new AssetInfo(jQueryKey, AssetType.Script, jQuerySrc)},
						{jQueryMetadataKey, new AssetInfo(jQueryMetadataKey, AssetType.Script, jQueryMetadataSrc)},
						{jQueryBgIframeKey, new AssetInfo(jQueryBgIframeKey, AssetType.Script, jQueryBgIframeSrc)},
						{jQueryUIKey, new AssetInfo(jQueryUIKey, AssetType.Script, jQueryUISrc)},
						{jQueryUIThemeKey, new AssetInfo(jQueryUIThemeKey, AssetType.Css, jQueryUIThemeSrc)},
						{jQueryValidateKey, new AssetInfo(jQueryValidateKey, AssetType.Script, jQueryValidateSrc)},
						{jQueryValidateAdditionalKey, new AssetInfo(jQueryValidateAdditionalKey, AssetType.Script, jQueryValidateAdditionalSrc)},
						{jQueryValidateMessagesKey, new AssetInfo(jQueryValidateMessagesKey, AssetType.Script, jQueryValidateMessagesSrc)},
						{jQueryMobileKey, new AssetInfo(jQueryMobileKey, AssetType.Script, jQueryMobileSrc)},
						{jQueryMobileThemeKey, new AssetInfo(jQueryMobileThemeKey, AssetType.Script, jQueryMobileThemeSrc)},
						{Base64Key, new AssetInfo(Base64Key, AssetType.Script, Base64Src)},
						{QSValuesKey, new AssetInfo(QSValuesKey, AssetType.Script, QSValuesSrc)},
						{SPHelpersKey, new AssetInfo(SPHelpersKey, AssetType.Script, SPHelpersSrc)},
						{SPUtilityKey, new AssetInfo(SPUtilityKey, AssetType.Script, SPUtilitySrc)},
						{UrlCodingKey, new AssetInfo(UrlCodingKey, AssetType.Script, UrlCodingSrc)},
						{FormsKey, new AssetInfo(FormsKey, AssetType.Css, FormsSrc)},
						{FormTabsKey, new AssetInfo(FormTabsKey, AssetType.Css, FormTabsSrc)}
					};
		}

		/// <summary>
		/// Return registration information class
		/// </summary>
		[MethodImpl(MethodImplOptions.Synchronized)]
		public static SyncDictionary<string, AssetRegistrationInfo> GetRegistrationInfo()
		{
			var store = RequestStore.GetStore();

			if (store == null)
				throw new PlatformNotSupportedException("HttpContext.Current is null! Component can be used only in ASP.NET!");

			return
				RequestStore.Get(
					"car-rc",
					key => new SyncDictionary<string, AssetRegistrationInfo>(StringComparer.OrdinalIgnoreCase));
		}

		/// <summary>
		/// Register client asset
		/// </summary>
		[MethodImpl(MethodImplOptions.Synchronized)]
		public static bool Register(string key)
		{
			return Register(key, null);
		}

		/// <summary>
		/// Register client asset
		/// </summary>
		[MethodImpl(MethodImplOptions.Synchronized)]
		public static bool Register(string key, string param)
		{
			var ca = Storage[key];

			if (ca == null)
				throw new ArgumentOutOfRangeException("key");

			var fullkey = param == null ? ca.Key : string.Format(ca.Key, param);

			var rc = GetRegistrationInfo();

			if (rc.ContainsKey(fullkey))
				return false;

			switch (ca.Type)
			{
				case AssetType.Script:
					ScriptLink.Register(WebExts.GetPage(), ca.Src, ca.Localizable, ca.Defer);
					break;

				case AssetType.Css:
					CssRegistration.Register(ca.Src, ca.EnableTheming);
					break;

				default:
					throw new ArgumentOutOfRangeException("ca.Type");
			}

			rc[fullkey] = new AssetRegistrationInfo(null, ca, param);

			return true;
		}

		/// <summary>
		/// Register script
		/// </summary>
		[MethodImpl(MethodImplOptions.Synchronized)]
		public static bool RegisterScript(string key, string src)
		{
			return RegisterScript(key, src, false, false);
		}

		/// <summary>
		/// Register script
		/// </summary>
		[MethodImpl(MethodImplOptions.Synchronized)]
		public static bool RegisterScript(string key, string src, bool localizable, bool defer)
		{
			var rc = GetRegistrationInfo();

			if (rc.ContainsKey(key))
				return false;

			ScriptLink.Register(WebExts.GetPage(), src, localizable, defer);

			rc[key] = new AssetRegistrationInfo(null, key, AssetType.Script, src);

			return true;
		}

		/// <summary>
		/// Register Css
		/// </summary>
		[MethodImpl(MethodImplOptions.Synchronized)]
		public static bool RegisterCss(string key, string src)
		{
			return RegisterCss(key, src, false);
		}

		/// <summary>
		/// Register Css
		/// </summary>
		[MethodImpl(MethodImplOptions.Synchronized)]
		public static bool RegisterCss(string key, string src, bool enableTheming)
		{
			var rc = GetRegistrationInfo();

			if (rc.ContainsKey(key))
				return false;

			CssRegistration.Register(src, enableTheming);

			rc[key] = new AssetRegistrationInfo(null, key, AssetType.Css, src);

			return true;
		}

		/// <summary>
		/// Register jQuery usage
		/// </summary>
		public static bool RegisterJQuery(bool metadata, bool bgiframe, bool ui, string uitheme, bool validate, string validatelang, bool mobile, string mobiletheme)
		{
			return
				Register(jQueryKey) ||
				(metadata && Register(jQueryMetadataKey)) ||
				(bgiframe && Register(jQueryBgIframeKey)) ||
				(ui && Register(jQueryUIKey)) ||
				(ui && Register(jQueryUIThemeKey, uitheme ?? "redmond")) ||
				(validate && Register(jQueryValidateKey)) ||
				(validate && Register(jQueryValidateAdditionalKey)) ||
				(validate && validatelang != null && Register(jQueryValidateMessagesKey, validatelang)) ||
				(mobile && Register(jQueryMobileKey)) ||
				(mobile && Register(jQueryMobileThemeKey, mobiletheme ?? "default"));
		}

		/// <summary>
		/// Register Utility usage
		/// </summary>
		public static bool RegisterUtility(bool sputility, bool base64, bool urlcoding, bool sphelpers, bool qsvalues)
		{
			return
				(sputility && RegisterJQuery(false, false, false, null, false, null, false, null)) ||
				(sputility && Register(SPUtilityKey)) ||
				(base64 && Register(Base64Key)) ||
				(urlcoding && Register(UrlCodingKey)) ||
				(sphelpers && Register(SPHelpersKey)) ||
				(qsvalues && Register(QSValuesKey));
		}

		/// <summary>
		/// Register Forms usage
		/// </summary>
		public static bool RegisterForms(bool forms, bool formtabs)
		{
			return
				(forms && Register(FormsKey)) ||
				(formtabs && Register(FormTabsKey));
		}
	}
}